// var curry = function(fn) {
//   console.log(arguments);
//   var args = [].slice.call(arguments, 1);
//   return function() {
//     var newArgs = args.concat([].slice.call(arguments));
//     // console.log(this); //this window
//     return fn.apply(this, newArgs);
//   };
// };

// function add(a, b) {
//   return a + b;
// }
// var addCurry = curry(add, 1, 2);
// console.log(addCurry());

function add1() {
  // 第一次执行时，定义一个数组专门用来存储所有的参数
  // var args = Array.prototype.slice.call(arguments);
  // var args = [...arguments];
  var args = Array.from(arguments);

  // 在内部声明一个函数，利用闭包的特性保存args并收集所有的参数值
  var adder = function() {
    // push() 方法将一个或多个元素添加到数组的末尾
    args.push(...arguments);
    return adder;
  };

  // 利用toString隐式转换的特性，当最后执行时隐式转换，并计算最终的值返回
  // 为adder函数重写他的toString方法
  // 在打印的瞬间调用toString方法
  adder.toString = function() {
    // reduce函数，a是之前元素的累加和，b是当前元素，
    return args.reduce(function(a, b) {
      return a + b;
    });
  }
  // adder.value = function() {
  //   // reduce函数，a是之前元素的累加和，b是当前元素，
  //   return args.reduce(function(a, b) {
  //     return a + b;
  //   });
  // }
  return adder;
}
// console.log(typeof add1(1)(2)(3)); // function
console.log(add1(1)(2)(3));      // 6
console.log(add1(1, 2, 3)(4));   // 10
console.log(add1(1)(2)(3)(4)(5));  // 15
console.log(add1(2, 6)(1));     // 9
console.log(add1(2, 6)(1, 3, 4));
// console.log(add1(1)(2, 3)(4).value());


// 柯里化函数
function curry(fn, args) {
  // 获取函数的形参个数 ，此处是3
  let length = fn.length;
  // 有参数等于参数 没有空数组 ,这里不能let ，args作为形参已经声明
  args = args || [];
  return function() {
    // 拼接传过来的参数 arguments是实参组成的伪数组
    // call 使得slice指向arguments 没有传入参数，截取arguments的全部元素
    // concat将之前的参数与现在的参数拼接
    // Array.prototype.slice也可以
    // let newArgs = args.concat([].slice.call(arguments));
    // let newArgs = args.concat(...arguments);
    let newArgs = args.concat(Array.from(arguments));
    // 判断参数的长度是否已经满足函数的形参个数
    if (newArgs.length < length) {
      // 不满足函数的参数个数 递归柯里化函数
      return curry.call(this, fn, newArgs);
    } else {
      // 满足函数的参数个数 执行函数
      return fn.apply(this, newArgs);
    }
  }
}
// 待柯里化的函数
function fn(a, b, c) {
  return a + b + c;
}
let add2 = curry(fn);
// 输出都是6
console.log(add2(1)(2)(3));
console.log(add2(1, 2, 3));
console.log(add2(1)(2, 3));
console.log(add2(1, 2)(3));
